import { h, ref, watch, onMounted, getCurrentInstance } from 'vue'
import { ElSkeleton } from 'element-plus'

export function LazyComp({ component, load }) {
  return {
    props: component.props,
    setup(props, context) {
      const flag = ref(true)
      // 监视回调函数
      const callback = (entires, observer) => {
        entires.forEach(entry => {
          if (entry.isIntersecting) {
            // 进入视口后改为false 用于取消骨架屏
            flag.value = false
            observer.unobserve(entry.target)
          }
        })
      }
      // 监视配置
      const options = {
        // 使用浏览器视口作为根元素
        root: null,
        // 没有边距偏移
        rootMargin: '0px',
        // 只有当目标元素完全进入视口才触发回调
        threshold: 1
      }
      // 实例化
      const observer = new IntersectionObserver(callback, options)
      // 获取this
      const instance = getCurrentInstance()
      // 元素挂载时启动监听 避免出现目标元素无法获的情况
      onMounted(() => {
        observer.observe(instance.ctx.$el)
      })
      // 是否处于加载状态
      const loading = ref(false)
      let data = {}
      // 通过监听flag的值来控制是否开始获取组件数据
      const unwatch = watch(
        () => flag.value,
        async flag => {
          if (!flag) {
            try {
              // 正在加载状态
              loading.value = true
              // 获取请求
              data = await load(instance.ctx.$props)
            } catch (error) {
              console.log(error)
            }
          }
          loading.value = false
          // 取消监听
          unwatch()
        }
      )

      return () => {
        // 数据正在请求/元素处于视口之外 使用骨架屏
        if (flag.value || loading.value) {
          return h(ElSkeleton, {
            animated: true
          })
        } else {
          return h(component, {
            ...instance.ctx.$props,
            store: data
          })
        }
      }
    }
  }
}
